home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / ck5a189s / ckcnet.c < prev    next >
C/C++ Source or Header  |  1993-06-13  |  50KB  |  1,786 lines

  1. char *cknetv = "Network support, 5A(019) 8 Jun 93";
  2.  
  3. /*  C K C N E T  --  Network support  */
  4. /*
  5.   Authors:
  6.  
  7.   Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  8.     Columbia University Center for Computing Activities.
  9.   netopen() routine for TCP/IP originally by Ken Yap, Rochester University
  10.     (ken@cs.rochester.edu) (no longer at that address).
  11.   Missing pieces for Excelan sockets library from William Bader, Moravian
  12.     College <bader@moravian.edu>.
  13.   TELNET protocol by Frank da Cruz.
  14.   TGV MultiNet code by Frank da Cruz.
  15.   MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
  16.   MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
  17.   TCP/IP support adapted to IBM TCP/IP 1.2.1 for OS/2 by Kai Uwe Rommel.
  18.   SunLink X.25 support by Marcello Frutig, Catholic University,
  19.     Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
  20.     Stefaan Eeckels, Eurokom, Luxembourg.
  21.   Other contributions as indicated below.
  22.  
  23.   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  24.   York.  Permission is granted to any individual or institution to use this
  25.   software as long as it is not sold for profit.  This copyright notice must be
  26.   retained.  This software may not be included in commercial products without
  27.   written permission of Columbia University.
  28. */
  29.  
  30. #include "ckcdeb.h"
  31. #include "ckcker.h"
  32. #ifdef I386IX                /* Has to come before ckcnet.h in */
  33. #include <errno.h>            /* this version, but after in others */
  34. #endif /* I386IX */
  35. #include "ckcnet.h"
  36.  
  37. #ifdef NETCONN
  38. /* Don't need these if there is no network support. */
  39.  
  40. #ifdef WINTCP
  41.  
  42. #include <errno.h>
  43. #include <setjmp.h>
  44. #include <signal.h>
  45. #include <sys/time.h>
  46. /*
  47.   The WIN/TCP code path is the same as that for MultiNet.
  48.   Only the routine names have changed ...
  49. */
  50. #define socket_errno     errno
  51. #define socket_read     netread
  52. #define socket_ioctl    ioctl
  53. #define socket_write     netwrite
  54. #define socket_perror   win$perror
  55. #define socket_close     netclose
  56.  
  57. #else /* Not WINTCP */
  58.  
  59. #ifndef I386IX
  60. #include <errno.h>            /* Already included above */
  61. #endif /* I386IX */
  62.  
  63. #include <signal.h>            /* Everybody needs this */
  64.  
  65. #ifdef ZILOG                /* Zilog has different name for this */
  66. #include <setret.h>
  67. #else /* !ZILOG */
  68. #include <setjmp.h>
  69. #endif /* ZILOG */
  70.  
  71. #endif /* WINTCP */
  72.  
  73. #ifdef datageneral            /* Data General AOS/VS */
  74. #include <:usr:include:vs_tcp_errno.h>
  75. #include <:usr:include:sys:vs_tcp_types.h>
  76. #include <:usr:include:sys:socket.h>
  77. #include <:usr:include:netinet:in.h>
  78. #include <:usr:include:netdb.h>
  79. #endif /* datageneral */
  80.  
  81. extern SIGTYP (*saval)();        /* For saving alarm handler */
  82.  
  83. _PROTOTYP( VOID bgchk, (void) );
  84.  
  85. extern int                /* External variables */
  86.   duplex, debses, seslog, ttyfd, quiet, msgflg;
  87.  
  88. #ifndef OS2
  89. #ifndef WINTCP
  90. jmp_buf njbuf;                /* For timeout longjumps */
  91. #endif /* OS2 */
  92. #endif /* WINTCP */
  93.  
  94. #ifdef SVR4
  95. /*
  96.   These suggested by Rob Healey, rhealey@kas.helios.mn.org, to avoid
  97.   bugs in Berkeley compatibility library on Sys V R4 systems, but untested
  98.   by me (fdc).  Remove this bit if it gives you trouble.
  99.   (Later corrected by Marc Boucher <mboucher@iro.umontreal.ca> because
  100.   bzero/bcopy are not argument-compatible with memset/memcpy|memmove.)
  101. */
  102. #define bzero(s,n) memset(s,0,n)
  103. #define bcopy(h,a,l) memmove(a,h,l)
  104. #else /* !SVR4 */
  105. #ifdef PTX                /* Sequent DYNIX PTX 1.3 */
  106. #define bzero(s,n) memset(s,0,n)
  107. #define bcopy(h,a,l) memcpy(a,h,l)
  108. #endif /* PTX */
  109. #endif /* SVR4 */
  110.  
  111. #define NAMECPYL 100            /* Local copy of hostname */
  112. static char namecopy[NAMECPYL];
  113.  
  114. char ipaddr[20] = { '\0' };        /* Global copy of IP address */
  115.  
  116. #endif /* NETCONN */
  117.  
  118. int ttnet = NET_NONE;            /* Network type */
  119. int ttnproto = NP_NONE;            /* Network virtual terminal protocol */
  120. int tn_init = 0;            /* Telnet protocol initialized flag */
  121. int tn_duplex = 1;            /* Initial echo status */
  122. char *tn_term = NULL;            /* Terminal type override */
  123. int tn_nlm = 1;                /* Telnet CR -> CR LF mode */
  124.  
  125. #ifndef NETCONN
  126. /*
  127.   Network support not defined.
  128.   Dummy functions here in case #ifdef's forgotten elsewhere.
  129. */
  130. int                    /* Open network connection */
  131. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  132.     return(-1);
  133. }
  134. int                    /* Close network connection */
  135. netclos() {
  136.     return(-1);
  137. }
  138. int                    /* Check network input buffer */
  139. nettchk() {
  140.     return(-1);
  141. }
  142. int                    /* Flush network input buffer */
  143. netflui() {
  144.     return(-1);
  145. }
  146. int                    /* Send network BREAK */
  147. netbreak() {
  148.     return(-1);
  149. }
  150. int                    /* Input character from network */
  151. netinc(timo) int timo; {
  152.     return(-1);
  153. }
  154. int                    /* Output character to network */
  155. #ifdef CK_ANSIC
  156. nettoc(char c)
  157. #else
  158. nettoc(c) char c;
  159. #endif /* CK_ANSIC */
  160. /* nettoc */ {
  161.     return(-1);
  162. }
  163. int
  164. nettol(s,n) char *s; int n; {
  165.     return(-1);
  166. }
  167.  
  168. #else /* NETCONN is defined (rest of this module...) */
  169. /*
  170.   TCPIPLIB means use separate socket calls, while on UNIX the
  171.   normal file system calls are used for TCP/IP sockets too,
  172.   i.e. "DEC_TCPIP or MULTINET or WINTCP or OS2" (defined in ckcnet.h).
  173. */
  174. #ifdef TCPIPLIB
  175.  
  176. /* For buffered network reads... */
  177. /*
  178.   If the buffering code is written right, it shouldn't matter how long this
  179.   buffer is -- it could even be shorter than a Kermit packet.
  180. */
  181. #define TTIBUFL 8192            /* Maybe 8K?... */
  182.  
  183. CHAR     ttibuf[TTIBUFL+1];
  184. int     ttibp = 0, ttibn = 0;
  185. /*
  186.   Read bytes from network into internal buffer ttibuf[].
  187.   To be called when input buffer is empty, i.e. when ttibn == 0.
  188.  
  189.   Other network reading routines, like ttinc, ttinl, ttxin, should check the
  190.   internal buffer first, and call this routine for a refill if necessary.
  191.  
  192.   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
  193.   returns number of bytes read, and sets global ttibn to that number and
  194.   ttibp (the buffer pointer) to zero.
  195. */
  196. int
  197. ttbufr() {                /* TT Buffer Read */
  198.     int count;
  199.  
  200.     if (ttnet != NET_TCPB) {        /* First make sure current net is */
  201.     return(-1);            /* TCP/IP; if not, do nothing. */
  202.     } else {
  203.     if (ttibn > 0)            /* Out internal buffer is not empty, */
  204.       return(ttibn);        /* so keep using it. */
  205. #ifdef WINTCP
  206.     count = 512;            /* This works for WIN/TCP */
  207. #else                    /* Not WINTCP, i.e it's Multinet */
  208. #ifdef DEC_TCPIP
  209.     count = 512;            /* This works for WIN/TCP */
  210. #else                    /* Not WINTCP, i.e it's Multinet */
  211.     count = nettchk();        /* Check network input buffer, */
  212.     if (ttibn > 0) return(ttibn);    /* which can put a char there! */
  213.     if (count < 0)            /* Read error */
  214.       return(-1);
  215.     else if (count > TTIBUFL)    /* Too many to read */
  216.       count = TTIBUFL;
  217.     else if (count == 0)        /* None, so force blocking read */
  218.       count = 1;
  219. #endif /* DEC_TCPIP */
  220. #endif /* WINTCP */
  221.     debug(F101,"ttbufr count 1","",count);
  222.  
  223. #ifdef COMMENT
  224. /*
  225.  This is for nonblocking reads, which we don't do any more.  This code didn't
  226.  work anyway, in the sense that a broken connection was never sensed.
  227. */
  228.     if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
  229.         if (count == -1 && socket_errno == EWOULDBLOCK) {
  230.         debug(F100,"ttbufr finds nothing","",0);
  231.         return(0);
  232.         } else {
  233.             debug(F101,"ttbufr socket_read error","",socket_errno);
  234.         return(-1);
  235.         }
  236.     } else if (count == 0) {
  237.         debug(F100,"ttbufr socket eof","",0);        
  238.         return(-1);
  239.     }
  240. #else
  241. /* This is for blocking reads */
  242.     if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
  243.         debug(F101,"ttbufr socket_read","",count);
  244.         debug(F101,"ttbufr socket_errno","",socket_errno);
  245.         return(-1);
  246.     }
  247. #endif /* COMMENT */
  248.     ttibp = 0;            /* Reset buffer pointer. */
  249.     ttibn = count;
  250. #ifdef DEBUG
  251.     debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
  252.     if (count > 0) ttibuf[count] = '\0';
  253.     debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
  254. #endif /* DEBUG */
  255.     return(ttibn);            /* Return buffer count. */
  256.     }
  257. }
  258. #endif /* TCPIPLIB */
  259.  
  260. /*
  261.   C-Kermit network open/close functions for BSD-sockets.
  262.   Much of this code shared by SunLink X.25, which also uses the socket library.
  263. */
  264.  
  265. /*  N E T O P E N  --  Open a network connection.  */
  266.  
  267. /*  Returns 0 on success, -1 on failure.  */
  268.  
  269. #define    TELNET_PORT    23       /* Should do lookup, but it won't change */
  270.  
  271. /* This symbol is not known to, e.g., Ultrix 2.0 */
  272. #ifndef TELOPT_TTYPE
  273. #define TELOPT_TTYPE 24
  274. #endif /* TELOPT_TTYPE */
  275.  
  276. /*  N E T O P N  --  Open a network connection.  */
  277. /*
  278.   Call with:
  279.     name of host (or host:service),
  280.     lcl - local-mode flag to be set if this function succeeds,
  281.     network type - value defined in ckunet.h.
  282. */
  283.  
  284. #ifdef TCPSOCKET
  285. #ifdef EXCELAN
  286. /*
  287.   Most other BSD sockets implementations define these in header files
  288.   and libraries.
  289. */
  290. struct servent {
  291.     unsigned short s_port;
  292. };
  293.  
  294. struct hostent {
  295.     short h_addrtype;
  296.     struct in_addr h_addr;
  297.     int h_length;
  298. };
  299.  
  300. struct servent *
  301. getservbyname(service, connection) char *service,*connection; {
  302.     static struct servent servrec;
  303.     int port;
  304.  
  305.     port = 0;
  306.     if (strcmp(service, "telnet") == 0) port = 23;
  307.     else if (strcmp(service, "smtp") == 0) port = 25;
  308.     else port = atoi(service);
  309.  
  310.     debug(F101,"getservbyname return port ","",port);
  311.  
  312.     if (port > 0) {
  313.         servrec.s_port = htons(port);
  314.         return( &servrec );
  315.     }
  316.     return( (struct servent *) NULL );
  317. }
  318.  
  319. struct hostent *
  320. gethostbyname(hostname) char *hostname; {
  321.     return( (struct hostent *) NULL );
  322. }
  323.  
  324. unsigned long
  325. inet_addr(name) char *name; {
  326.     unsigned long addr;
  327.  
  328.     addr = rhost(&name);
  329.     debug(F111,"inet_addr ",name,(int)addr);
  330.     return(addr);
  331. }
  332.  
  333. char *
  334. inet_ntoa(in) struct in_addr in; {
  335.     static char name[80];
  336.     sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
  337.     return(name);
  338. }
  339. #endif /* EXCELAN */
  340. #endif /* TCPSOCKET */
  341.  
  342. /*  N E T O P E N  --  Open a network connection  */
  343. /*
  344.   Calling conventions same as ttopen(), except third argument is network
  345.   type rather than modem type.  Designed to be called from within ttopen.
  346. */
  347. int
  348. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  349.     char *p;
  350.     int i, x;
  351. #ifdef TCPSOCKET
  352. #ifdef SO_OOBINLINE
  353.     int on = 1;
  354. #endif /* SO_OOBINLINE */
  355. #ifdef __IBMC__
  356.     _Packed struct servent *service, servrec;
  357. #else
  358.     struct servent *service, servrec;
  359. #endif /* __IBMC__ */
  360.     struct hostent *host;
  361.     struct sockaddr_in saddr;
  362. #ifdef EXCELAN
  363.     struct sockaddr_in send_socket;
  364. #endif /* EXCELAN */
  365. #endif /* TCPSOCKET */
  366.  
  367. #ifdef SUNX25                /* Code for SunLink X.25 support */
  368. #define X29PID 1            /* X.29 Protocol ID */
  369.     VOID x25oobh();
  370.     CONN_DB x25host;
  371.     FACILITY_DB x25facil;
  372.     static int needh = 1;
  373.     PID_T pid;
  374.     extern int linkid, lcn, x25ver;
  375.     extern int revcall, closgr, cudata;
  376.     extern char udata[MAXCUDATA];
  377. #endif /* SUNX25 */
  378.  
  379.     debug(F101,"netopen nett","",nett);
  380.     *ipaddr = '\0';            /* Initialize IP address string */
  381.  
  382. #ifdef SUNX25
  383.     if (nett == NET_SX25) {        /* If network type is X.25 */
  384.         netclos();            /* Close any previous net connection */
  385.         ttnproto = NP_NONE;        /* No protocol selected yet */
  386.  
  387.         /* Set up host structure */
  388.         bzero ((char *)&x25host,sizeof(x25host));
  389.         if ((x25host.hostlen = pkx121 (name,x25host.host)) < 0) {
  390.             fprintf (stderr,"Invalid X.121 host address %s\n",name);
  391.             errno = 0;
  392.             return (-1);
  393.         }
  394.         x25host.datalen = X29PIDLEN;
  395.         x25host.data[0] = X29PID;
  396.  
  397.     /* Set call user data if specified */
  398.         if (cudata) {
  399.             strncpy(x25host.data+X29PIDLEN,udata,(int)strlen(udata));
  400.             x25host.datalen += (int)strlen(udata);
  401.         }
  402.  
  403.         /* Open SunLink X.25 socket */
  404.         if ((ttyfd = socket (AF_X25, SOCK_STREAM, 0)) < 0) {
  405.         debug(F101,"netopen socket error","",errno);
  406.             perror ("X.25 connect socket error");
  407.             return (-1);
  408.         }
  409.  
  410.         /* Setting X.25 out-of-band data handler */
  411.         pid = getpid();
  412.         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
  413.             perror("Setting process group id");
  414.             return(-1);
  415.         }
  416.         (VOID) signal(SIGURG,x25oobh);
  417.  
  418.         /* Set reverse charge call and closed user group if requested */
  419.         bzero ((char *)&x25facil,sizeof(x25facil));
  420.         if (revcall) x25facil.reverse_charge = revcall;
  421.         if (closgr > -1) {
  422.             x25facil.cug_req = 1;
  423.             x25facil.cug_index = closgr;
  424.         }
  425.         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
  426.             perror ("Setting X.25 facilities");
  427.             return (-1);
  428.         }
  429.  
  430.         /*  Need X.25 header with bits Q and M */
  431.         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
  432.             perror ("Setting X.25 header");
  433.             return (-1);
  434.         }
  435.  
  436.         /* Connects to remote host via SunLink X.25 */
  437.         if (connect(ttyfd,&x25host,sizeof(x25host)) < 0) {
  438.             debug(F101,"netopen connect errno","",errno);
  439.             i = errno;
  440.         if (errno) {
  441.                 perror("netopen");
  442.                 x25diag();
  443.             }
  444.             (VOID) close (ttyfd);
  445.             ttyfd = -1;
  446.             errno = i;
  447.             return (-1);
  448.         }
  449.  
  450.         /* Get X.25 link identification used for the connection */
  451.         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
  452.             perror ("Getting X.25 link id");
  453.             return (-1);
  454.         }
  455.  
  456.         /* Get X.25 logical channel number used for the connection */
  457.         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
  458.             perror ("Getting X.25 lcn");
  459.             return (-1);
  460.         }
  461.  
  462.         /* Get SunLink X.25 version */
  463.         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
  464.             perror ("Getting SunLink X.25 version");
  465.             return (-1);
  466.         }
  467.         ttnet = nett;                   /* Sunlink X.25 network */
  468.         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
  469.         if (*lcl < 0) *lcl = 1;         /* Local mode */
  470.         return(0);
  471.     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
  472. #endif /* SUNX25 */
  473. /*
  474.   Add support for other networks here.
  475. */
  476.     if (nett != NET_TCPB) return(-1);    /* BSD socket support */
  477.  
  478. #ifdef TCPSOCKET
  479.     netclos();                /* Close any previous connection. */
  480.     strncpy(namecopy, name, NAMECPYL);    /* Copy the hostname. */
  481.     ttnproto = NP_NONE;            /* No protocol selected yet. */
  482.     debug(F110,"netopen namecopy",namecopy,0);
  483.  
  484.     p = namecopy;            /* Was a service requested? */
  485.     while (*p != '\0' && *p != ':') p++; /* Look for colon */
  486.     if (*p == ':') {            /* Have a colon */
  487.     *p++ = '\0';            /* Get service name or number */
  488.     } else {                /* Otherwise use telnet */
  489.     p = "telnet";
  490.     }
  491.     debug(F110,"netopen service requested",p,0);
  492.     if (isdigit(*p)) {            /* Use socket number without lookup */
  493.     service = &servrec;
  494.     service->s_port = htons((unsigned short)atoi(p));
  495.     } else {                /* Otherwise lookup the service name */
  496.     service = getservbyname(p, "tcp");
  497.     }
  498.     if (!service) {
  499.     fprintf(stderr, "Cannot find port for service %s\n", p);
  500. #ifdef MULTINET
  501.     debug(F101,"netopen can't get service","",socket_errno);
  502. #else
  503.     debug(F101,"netopen can't get service","",errno);
  504. #endif /* MULTINET */
  505.     errno = 0;            /* rather than mislead */
  506.     return(-1);
  507.     }
  508.     /* Set up socket structure and get host address */
  509.  
  510.     bzero((char *)&saddr, sizeof(saddr));
  511.     if ((host = gethostbyname(namecopy)) != NULL) {
  512.     saddr.sin_family = host->h_addrtype;
  513.     bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
  514.     } else {
  515. #ifdef INADDRX
  516. /* inet_addr() is of type struct in_addr */
  517.     struct in_addr ina;
  518.     unsigned long uu;
  519. #ifdef datageneral
  520.         extern struct in_addr inet_addr();
  521. #endif /* datageneral */
  522.     ina = inet_addr(namecopy);
  523.     uu = *(unsigned long *)&ina;
  524. #else /* Not INADDRX */
  525. /* inet_addr() is unsigned long */
  526.     unsigned long uu;
  527.     uu = inet_addr(namecopy);
  528. #endif /* INADDRX */
  529.     if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
  530.       saddr.sin_family = AF_INET;
  531.     else {
  532.       fprintf(stderr, "Can't get address for %s\n", namecopy);
  533. #ifdef MULTINET
  534.       debug(F101,"netopen can't get address","",socket_errno);
  535. #else
  536.       debug(F101,"netopen can't get address","",errno);
  537. #endif /* MULTINET */
  538.       errno = 0;            /* rather than mislead */
  539.       return(-1);
  540.       }
  541.     }
  542.  
  543.     /* Get a file descriptor for the connection. */
  544.  
  545.     saddr.sin_port = service->s_port;
  546.     sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
  547.     if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
  548.  
  549. #ifdef EXCELAN
  550.     send_socket.sin_family = AF_INET;
  551.     send_socket.sin_addr.s_addr = 0;
  552.     send_socket.sin_port = 0;
  553.     if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
  554.         &send_socket, SO_REUSEADDR)) < 0)
  555. #else
  556.     if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  557. #endif /* EXCELAN */
  558.       {
  559. #ifdef EXCELAN
  560.     experror("TCP socket error");
  561. #else
  562. #ifdef MULTINET
  563.      socket_perror("TCP socket error");
  564.     debug(F101,"netopen socket error","",socket_errno);
  565. #else
  566.      perror("TCP socket error");
  567.     debug(F101,"netopen socket error","",errno);
  568. #endif /* MULTINET */
  569. #endif /* EXCELAN */
  570.     return (-1);
  571.     }
  572.     errno = 0;
  573.  
  574.     /* Now connect to the socket on the other end. */
  575.  
  576. #ifdef EXCELAN
  577.     if (connect(ttyfd, &saddr) < 0)
  578. #else
  579.     if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
  580. #endif /* EXCELAN */
  581.       {
  582.     i = errno;            /* save error code */
  583.     close(ttyfd);
  584.     ttyfd = -1;
  585.     errno = i;            /* and report this error */
  586. #ifdef EXCELAN
  587.     if (errno) experror("netopen connect");
  588. #else
  589. #ifdef MULTINET
  590.     debug(F101,"netopen connect error","",socket_errno);
  591.     if (errno) socket_perror("netopen connect");
  592. #else
  593.     debug(F101,"netopen connect errno","",errno);
  594. #ifdef    WINTCP
  595.     perror("netopen connect");
  596. #endif    /* WINTCP */
  597. #ifdef DEC_TCPIP
  598.     perror("netopen connect");
  599. #endif /* DEC_TCPIP */
  600. #endif /* MULTINET */
  601. #endif /* EXCELAN */
  602.     return(-1);
  603.     }
  604. #ifdef SO_OOBINLINE
  605. /*
  606.   The symbol SO_OOBINLINE is not known to Ultrix 2.0.
  607.   It means "leave out of band data inline".  The normal value is 0x0100,
  608.   but don't try this on systems where the symbol is undefined.
  609. */
  610. #ifdef datageneral
  611.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  612. #else
  613. #ifdef BSD43
  614.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  615. #else
  616. #ifdef OSF1
  617.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  618. #else
  619. #ifdef POSIX
  620.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  621. #else
  622. #ifdef SOLARIS
  623. /*
  624.   Maybe this applies to all SVR4 versions, but the other (else) way has been
  625.   compiling and working fine on all the others, so best not to change it.
  626. */
  627.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  628. #else
  629. #ifdef OS2
  630.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  631. #else
  632.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
  633. #endif /* OS2 */
  634. #endif /* SOLARIS */
  635. #endif /* POSIX */
  636. #endif /* BSD43 */
  637. #endif /* OSF1 */
  638. #endif /* datageneral */
  639. #endif /* SO_OOBINLINE */
  640.  
  641.     /* See if the service is TELNET. */
  642.     if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT)
  643.       ttnproto = NP_TELNET;        /* Yes, set global flag. */
  644.     debug(F101,"netopen service","",x);
  645.     ttnet = nett;            /* TCP/IP (sockets) network */
  646.     tn_init = 0;            /* Telnet protocol not init'd yet */
  647.     if (*lcl < 0) *lcl = 1;        /* Local mode. */
  648. #endif /* TCPSOCKET */
  649.     return(0);                /* Done. */
  650. }
  651.  
  652. /*  N E T C L O S  --  Close current network connection.  */
  653.  
  654. int
  655. netclos() {
  656.     int x = 0;
  657.     if (ttyfd < 0)            /* Was open? */
  658.       return(0);            /* Wasn't. */
  659.     if (ttyfd > -1)            /* Was. */
  660. #ifdef TCPIPLIB
  661.       x = socket_close(ttyfd);        /* Close it. */
  662. #else
  663.       x = close(ttyfd);
  664. #endif /* TCPIPLIB */
  665.     ttyfd = -1;                /* Mark it as closed. */
  666.     tn_init = 0;            /* Remember about telnet protocol... */
  667.     *ipaddr = '\0';            /* Zero the IP address string */
  668.     return(x);
  669. }
  670.  
  671. /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
  672. /*
  673.   Returns number of bytes waiting, or -1 if connection has been dropped.
  674. */
  675. int                    /* Check how many bytes are ready */
  676. nettchk() {                /* for reading from network */
  677. #ifdef TCPIPLIB
  678.     unsigned long count = 0;
  679.     int x;
  680.     long y;
  681.     char c;
  682.  
  683.     debug(F101,"nettchk entry ttibn","",ttibn);
  684.     debug(F101,"nettchk entry ttibp","",ttibp);
  685.     socket_errno = 0;
  686. /*
  687.   Note: this socket_ioctl() call does NOT return an error if the
  688.   connection has been broken.  (At least not in Multinet.)
  689. */
  690.     if (socket_ioctl(ttyfd,FIONREAD,&count) < 0) {
  691.     debug(F101,"nettchk socket_ioctl error","",socket_errno);
  692.     if (ttibn < 1) return(-1);
  693.     else return(ttibn);
  694.     }
  695.     debug(F101,"nettchk count","",count);
  696.  
  697. #ifndef DEC_TCPIP
  698. /*
  699.   Let's see if we can skip this for UCX, since it seems to cause trouble.
  700. */
  701.     if (count == 0) {
  702. /*
  703.   Here we need to tell the difference between a 0 count on an active
  704.   connection, and a 0 count because the remote end of the socket broke the
  705.   connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
  706.   the status of the connection, so we have to do a read.  -1 means there was
  707.   no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
  708.   down.  But if, by chance, we actually get a character, we have to put it
  709.   where it won't be lost.
  710. */
  711.     y = 1;                /* Turn on nonblocking reads */
  712.     debug(F101,"nettchk before FIONBIO","",x);
  713.     x = socket_ioctl(ttyfd,FIONBIO,&y);
  714.     debug(F101,"nettchk FIONBIO","",x);
  715.     x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
  716.     debug(F101,"nettchk socket_read","",x);
  717.     y = 0;                /* Turn them back off */
  718.     socket_ioctl(ttyfd,FIONBIO,&y);
  719.     if (x == 0) return(-1);        /* Connection is broken. */
  720.     if (x == 1) {            /* Oops, actually got a byte? */
  721.         debug(F101,"nettchk socket_read char","",c);
  722.         debug(F101,"nettchk ttibp","",ttibp);
  723.         debug(F101,"nettchk ttibn","",ttibn);
  724. /*
  725.   So put the byte we got into the buffer at the current position.
  726.   Increment the buffer count, but DON'T increment the buffer pointer.
  727. */
  728.         ttibuf[ttibp+ttibn] = c;
  729.         ttibn++;
  730. #ifdef DEBUG
  731.         ttibuf[ttibp+ttibn] = '\0';
  732.         debug(F111,"nettchk ttibn",ttibuf,ttibn);
  733. #endif /* DEBUG */
  734.     }
  735.     }
  736. #endif /* DEC_TCPIP */
  737.     debug(F101,"nettchk returns","",count+ttibn);
  738.     return(count + ttibn);
  739.  
  740. #else /* Not TCPIPLIB */
  741. /*
  742.   UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
  743.   seem to work OK.
  744. */
  745.     return(0);
  746. #endif /* TCPIPLIB */
  747. /*
  748.   But what about X.25?
  749. */
  750. }
  751.  
  752. #ifndef OS2
  753. #ifndef WINTCP
  754. VOID
  755. nettout(i) int i; {            /* Catch the alarm interrupts */
  756.     debug(F100,"nettout caught timeout","",0);
  757.     ttimoff();
  758.     longjmp(njbuf, -1);
  759. }
  760. #endif /* !WINTCP */
  761. #endif /* !OS2 */
  762.  
  763. /*  N E T I N C --  Input character from network */
  764.  
  765. int            
  766. netinc(timo) int timo; {
  767. #ifdef TCPIPLIB
  768.     int x; unsigned char c;        /* The locals. */
  769.  
  770.     if (ttibn > 0) {            /* Something in internal buffer? */
  771.     debug(F100,"netinc char in buf","",0); /* Yes. */
  772.     x = 0;                /* Success. */
  773.     } else {                /* Else must read from network. */
  774.     x = -1;                /* Assume failure. */
  775. #ifdef DEBUG
  776.     debug(F101,"netinc goes to net, timo","",timo);
  777.     ttibuf[ttibp+1] = '\0';
  778.     debug(F111,"netinc ttibuf",ttibuf,ttibp);
  779. #endif /* DEBUG */
  780.     if (timo == 0) {        /* Untimed case. */
  781.         while (1) {            /* Wait forever if necessary. */
  782.         if (ttbufr() < 0)    /* Refill buffer. */
  783.           break;        /* Error, fail. */
  784.         if (ttibn > 0) {    /* Success. */
  785.             x = 0;
  786.             break;
  787.         }
  788.         }
  789.     } else {            /* Timed case... */
  790. /*
  791.   select() is used in preference to alarm()/signal(), but different systems
  792.   use different forms of select()...
  793. */
  794. #ifdef WINTCP                /* VMS with Wollongong WIN/TCP */
  795. #define BSDSELECT
  796. #endif /* WINTCP */
  797.  
  798. #ifdef OS2                /* OS/2 with IBM TCP/IP */
  799. #ifdef TCPIBM
  800. #ifndef BSDSELECT
  801. #define IBMSELECT
  802. #endif /* BSDSELECT */
  803. #endif /* TCPIBM */
  804. #endif /* OS2 */
  805. /*
  806.   Others (UCX, TGV) use alarm()/signal().  The BSDSELECT case does not
  807.   compile at all; the IBMSELECT case compiles and links but crashes at
  808.   runtime.
  809. */
  810.  
  811. #ifdef BSDSELECT
  812.             fd_set rfds;
  813.             struct timeval tv;
  814.             FD_ZERO(&rfds);
  815.             FD_SET(ttyfd, &rfds);
  816.             tv.tv_sec  = tv.tv_usec = 0L;
  817.             if (timo < 0)
  818.               tv.tv_usec = (long) -timo * 10000L;
  819.             else
  820.               tv.tv_sec = timo;
  821.         debug(F101,"netinc BSDSELECT","",timo);
  822.             if ( select(FD_SETSIZE, &rfds, NULL, NULL, &tv) &&
  823.                  FD_ISSET(ttyfd, &rfds) )
  824. #else /* !BSDSELECT */
  825. #ifdef IBMSELECT
  826.             short socket = ttyfd;
  827.         debug(F101,"netinc IBMSELECT","",timo);
  828.             if ( select(&socket, 1, 0, 0,
  829.                         timo < 0 ? -timo * 10 : timo * 1000L) == 1)
  830. #else /* !IBMSELECT */
  831. /*
  832.   If we can't use select(), then we use the regular alarm()/signal()
  833.   timeout mechanism.
  834. */
  835.         debug(F101,"netinc alarm","",timo);
  836.         saval = signal(SIGALRM,nettout); /* Enable timer interrupt */
  837.         alarm(timo);        /* for requested interval. */
  838.         if (setjmp(njbuf)) {    /* Timer went off? */
  839.         x = -1;            /* Yes, fail. */
  840.         } else {
  841. #endif /* IBMSELECT */
  842. #endif /* BSDSELECT */
  843.         while (1) {
  844.             if (ttbufr() < 0)    /* Keep trying to refill it. */
  845.               break;        /* Till we get an error. */
  846.             if (ttibn > 0) {    /* Or we get a character. */
  847.             x = 0;
  848.             break;
  849.             }
  850.         }
  851. #ifndef BSDSELECT
  852. #ifndef IBMSELECT
  853.         }
  854.         ttimoff();            /* Timer off. */
  855. #endif /* IBMSELECT */
  856. #endif /* BSDSELECT */
  857.     }
  858.     }
  859.     if (x < 0) {            /* Return -1 if we failed. */
  860.     debug(F100,"netinc timed out","",0);
  861.     return(-1);
  862.     } else {                /* Otherwise */
  863.     ttibn--;            /* Return what we got. */
  864.     c = ttibuf[ttibp++];
  865.     debug(F101,"netinc returning","",c);
  866.     return((c & 0xff));
  867.     }
  868. #else /* Not MULTINET or WINTCP */
  869.     return(-1);
  870. #endif /* TCPIPLIB */
  871. }
  872.  
  873. /*  N E T T O L  --  Output a string of bytes to the network  */
  874. /*
  875.   Call with s = pointer to string, n = length.
  876.   Returns number of bytes actually written on success, or
  877.   -1 on i/o error, -2 if called improperly.
  878. */
  879. int
  880. nettol(s,n) char *s; int n; {
  881. #ifdef TCPIPLIB
  882.     int count;
  883.     if (ttnet == NET_TCPB) {
  884.     if ((count = socket_write(ttyfd,s,n)) < 1) {
  885.         debug(F101,"nettol socket_write error","",socket_errno);
  886.         return(-1);
  887.     }
  888.     debug(F111,"nettol socket_write",s,count);
  889.     return(count);
  890.     } else return(-2);
  891. #else
  892.     debug(F100,"nettol TCPIPLIB not defined","",0);
  893.     return(-2);
  894. #endif /* TCPIPLIB */
  895. }
  896.  
  897. /*  N E T T O C  --   Output character to network */
  898. /*
  899.   Call with character to be transmitted.
  900.   Returns 0 if transmission was successful, or
  901.   -1 upon i/o error, or -2 if called improperly.
  902. */
  903. int            
  904. #ifdef CK_ANSIC
  905. nettoc(char c)
  906. #else
  907. nettoc(c) char c;
  908. #endif /* CK_ANSIC */
  909. /* nettoc */ {
  910. #ifdef TCPIPLIB
  911.     unsigned char cc;
  912.     cc = c;
  913.     if (ttnet == NET_TCPB) {
  914.     debug(F101,"nettoc cc","",cc);
  915.     if (socket_write(ttyfd,&cc,1) < 1) {
  916.         debug(F101,"nettoc socket_write error","",socket_errno);
  917.         return(-1);
  918.     }
  919.     debug(F101,"nettoc socket_write","", cc);
  920.     return(0);
  921.     } else return(-2);
  922. #else
  923.     return(-2);
  924. #endif /* TCPIPLIB */
  925. }
  926.  
  927. /*  N E T F L U I  --  Flush network input buffer  */
  928.  
  929. int
  930. netflui() {
  931.     int n;
  932. #ifdef TCPIPLIB
  933.     ttibuf[ttibp+1] = '\0';
  934.     debug(F111,"netflui 1",ttibuf,ttibn);
  935.     ttibn = ttibp = 0;            /* Flush internal buffer *FIRST* */
  936.     if ((n = nettchk()) > 0) {        /* Now see what's waiting on the net */
  937.     if (n > TTIBUFL) n = TTIBUFL;    /* and sponge it up */
  938.     debug(F101,"netflui 2","",n);    /* ... */
  939.     n = socket_read(ttyfd,ttibuf,n) ; /* into our buffer */
  940.     if (n >= 0) ttibuf[n] = '\0';
  941.     debug(F111,"netflui 3",ttibuf,n);
  942.     ttibuf[0] = '\0';
  943.     }
  944. #else
  945. /*
  946.   It seems the UNIX ioctl()s don't do the trick, so we have to read the
  947.   stuff ourselves.  This should be pretty much portable, if not elegant.
  948. */
  949.     if ((n = ttchk()) > 0) {
  950.     debug(F101,"netflui","",n);
  951.     while ((n--) && ttinc(0) > -1) ; /* Don't worry, it's buffered. */
  952.     }
  953. #endif /* TCPIPLIB */
  954.     return(0);
  955. }
  956.  
  957. #ifdef TNCODE                /* Compile in telnet support code */
  958.  
  959. /* TCP/IP TELNET protocol negotiation support code */
  960.  
  961. static int sgaflg = 0;            /* SUPRRESS GO-AHEAD state */
  962. static int dosga  = 0;            /* 1 if I sent DO SGA from tn_ini() */
  963. static int wttflg = 0;            /* ditto for WILL TERMINAL TYPE */
  964.  
  965. #ifndef TELCMDS
  966. char *telcmds[] = {
  967.     "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
  968.     "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC",
  969. };
  970. int ntelcmds = sizeof(telcmds) / sizeof(char *);
  971. #endif /* TELCMDS */
  972.  
  973. #ifndef TELOPTS
  974. char *telopts[] = {
  975.     "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
  976.     "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
  977.     "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
  978.     "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
  979.     "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
  980.     "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD"
  981. #ifdef TELOPT_TUID
  982.     ,"TACACS UID"
  983. #ifdef TELOPT_OUTMRK
  984.     ,"OUTPUT MARKING"
  985. #ifdef TELOPT_TTYLOC
  986.     ,"TTYLOC"
  987. #ifdef TELOPT_3270REGIME
  988.     ,"3270 REGIME"
  989. #ifdef TELOPT_X3PAD
  990.     ,"X.3 PAD"
  991. #ifdef TELOPT_NAWS
  992.     ,"NAWS"
  993. #ifdef TELOPT_TSPEED
  994.     ,"TSPEED"
  995. #ifdef TELOPT_LFLOW
  996.     ,"LFLOW"
  997. #ifdef TELOPT_LINEMODE
  998.     ,"LINEMODE"
  999. #endif
  1000. #endif
  1001. #endif
  1002. #endif
  1003. #endif
  1004. #endif
  1005. #endif
  1006. #endif
  1007. #endif
  1008. };
  1009. #endif /* TELOPTS */
  1010.  
  1011. int ntelopts = sizeof(telopts) / sizeof(char *);
  1012. #endif /* TNCODE */
  1013.  
  1014. /* Send network BREAK */
  1015. /*
  1016.   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
  1017. */
  1018. int
  1019. netbreak() {
  1020.     CHAR buf[3];
  1021.     if (ttnet == NET_TCPB) {
  1022.     if (ttnproto == NP_TELNET) {
  1023. #ifdef TNCODE
  1024.         buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK;
  1025.         if (ttol(buf,2) < 2) return(-1);
  1026.         debug(F101,"telnet BREAK ok","",BREAK);
  1027.         return(1);
  1028. #else
  1029.         debug(F100,"netbreak no TNCODE","",0);
  1030.         return(0);
  1031. #endif /* TNCODE */
  1032.     }
  1033.     /* Insert other TCP/IP protocols here */
  1034.     }
  1035.     /* Insert other networks here */
  1036.     return(0);
  1037. }
  1038.  
  1039. /* Send a telnet option, avoid loops. */
  1040. /* Returns 1 if command was sent, 0 if not, -1 on error */
  1041.  
  1042. int
  1043. tn_sopt(cmd,opt) int cmd, opt; {    /* TELNET SEND OPTION */
  1044.     CHAR buf[4];
  1045.     int n;
  1046.     if (ttnet != NET_TCPB) return(0);    /* Must be TCP/IP */
  1047.     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
  1048. #ifdef TNCODE
  1049.     n = cmd - SE;
  1050.     if (n < 0 || n > ntelcmds) return(0);
  1051.     buf[0] = (CHAR) IAC;
  1052.     buf[1] = (CHAR) cmd & 0xff;
  1053.     buf[2] = (CHAR) opt & 0xff;
  1054.     if (ttol(buf,3) < 3)
  1055.       return(-1);
  1056.     debug(F111,"telnet cmd >",telcmds[n],cmd);
  1057.     debug(F111,"telnet opt >",
  1058.        ((opt < ntelopts) ? telopts[opt] : "UNKNOWN"), opt );
  1059.     if (debses && cmd != SB)
  1060.       printf("[%s %s]",telcmds[n],
  1061.          (opt < ntelopts) ? telopts[opt] : "UNKNOWN");
  1062.     return(1);
  1063. #else
  1064.     debug(F100,"tn_sopt no TNCODE","",0);
  1065.     return(0);
  1066. #endif /* TNCODE */
  1067. }
  1068.  
  1069. /* Initialize a telnet connection. */
  1070. /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
  1071.  
  1072. int
  1073. tn_ini() {
  1074. #ifndef TNCODE
  1075.     debug(F100,"tn_ini no TNCODE","",0);
  1076.     return(0);
  1077. #else /* TELNET protocol support */
  1078.     debug(F101,"tn_ini ttnproto","",ttnproto);
  1079.     debug(F101,"tn_ini tn_init","",tn_init);
  1080.  
  1081.     if (ttnet != NET_TCPB)        /* Make sure connection is TCP/IP. */
  1082.       return(0);
  1083.     if (tn_init)            /* Have we done this already? */
  1084.       return(0);            /* Don't do it again. */
  1085.     debug(F101,"tn_ini tn_duplex","",tn_duplex);
  1086.     duplex = tn_duplex;            /* Assume local echo. */
  1087.     sgaflg = 0;                /* Assume Go-Ahead suppressed. */
  1088.     wttflg = 0;                /* Did not send WILL TERM TYPE yet. */
  1089.     dosga  = 0;                /* Did not send DO SGA yet. */
  1090.     if (ttnproto == NP_NONE) {        /* If not talking to a telnet port, */
  1091.     ttnproto = NP_TELNET;        /* pretend it's telnet anyway, */
  1092.     tn_init = 1;            /* but don't send initial options. */
  1093.     debug(F100,"tn_ini skipping telnet negotiations","",0);
  1094.     return(0);
  1095.     }
  1096.     /* Talking to telnet port, so send WILL TERMINAL TYPE and DO SGA */
  1097.  
  1098.     if (tn_sopt(WILL,TELOPT_TTYPE) < 0)    /* Will send terminal type. */
  1099.       return(-1);
  1100.     wttflg = 1;                /* Remember I said I would. */
  1101.     if (tn_sopt(DO,TELOPT_SGA) < 0)    /* Please suppress go-ahead. */
  1102.       return(-1);
  1103.     dosga = 1;                /* Remember I send DO SGA */
  1104.     tn_init = 1;            /* Set telnet-initialized flag. */
  1105.  
  1106.     /* Don't send anthing else! */
  1107.  
  1108.     debug(F101,"tn_ini duplex","",duplex);
  1109.     return(1);
  1110. #endif /* TNCODE */
  1111. }
  1112.  
  1113. /*
  1114.   Process in-band Telnet negotiation characters from the remote host.
  1115.   Call with the telnet IAC character and the current duplex setting
  1116.   (0 = remote echo, 1 = local echo).
  1117.   Returns:
  1118.     3 if server has sent us a quoted IAC
  1119.     2 if local echo must be changed to remote
  1120.     1 if remote echo must be changed to local
  1121.     0 if nothing happens or no action necessary
  1122.    -1 on failure (= internal or i/o error)
  1123. */
  1124.  
  1125. #define TSBUFSIZ 41
  1126. char sb[TSBUFSIZ];            /* Buffer for subnegotiations */
  1127.  
  1128. int
  1129. #ifdef CK_ANSIC                /* TELNET DO OPTION */
  1130. tn_doop( CHAR z, int echo, int (*fn)(int) )
  1131. #else
  1132. tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)();
  1133. #endif /* CK_ANSIC */
  1134. /* tn_doop */ {
  1135.     int c, x, y, n, m, flag;
  1136.  
  1137. #ifndef TNCODE
  1138.     debug(F100,"tn_doop no TNCODE","",0);
  1139.     return(0);
  1140. #else
  1141.     if (z != (CHAR) IAC) {
  1142.     debug(F101,"tn_doop bad call","",z);
  1143.     return(-1);
  1144.     }
  1145.     if (ttnet != NET_TCPB) return(0);
  1146.     if (ttnproto != NP_TELNET) return(0);     /* Check protocol */
  1147.  
  1148. /* Have IAC, read command character. */
  1149.  
  1150.     c = (*fn)(0) & 0xff;        /* Read command character */
  1151.     m = c - SE;                /* Check validity */
  1152.     if (m < 0 || m > ntelcmds) {
  1153.     debug(F101,"tn_doop bad cmd","",c);
  1154.     return(0);
  1155.     }
  1156.     if (seslog) {            /* Copy to session log, if any. */
  1157.     if (zchout(ZSFILE, (char) z) < 0) seslog = 0; /* Log IAC. */
  1158.     else if (zchout(ZSFILE, (char) c) < 0) seslog = 0; /* Log command */
  1159.     }
  1160.     debug(F111,"telnet cmd <",telcmds[m],c); /* Debug log. */
  1161.  
  1162.     if (c == (CHAR) IAC) return(3);    /* Quoted IAC */
  1163.     if (c < SB) return(0);        /* Other command with no arguments. */
  1164.  
  1165. /* SB, WILL, WONT, DO, or DONT need more bytes... */
  1166.  
  1167.     if ((x = (*fn)(0)) < 0) return(-1);    /* Get the option. */
  1168.     x &= 0xff;                /* Trim to 8 bits. */
  1169.  
  1170.     debug(F111,"telnet opt <",
  1171.       ((x < ntelopts) ? telopts[x] : "UNKNOWN"), x );
  1172.     if (seslog)                /* Session log */
  1173.       if (zchout(ZSFILE, (char) x) < 0) seslog = 0;
  1174.  
  1175.     /* Now handle the command */
  1176.  
  1177.     if (debses && c != SB)         /* Debug to screen. */
  1178.       printf("<%s %s>",telcmds[m],
  1179.          (x < ntelopts) ? telopts[x] : "UNKNOWN" );
  1180.     switch (x) {
  1181.       case TELOPT_ECHO:            /* ECHO negotiation. */
  1182.     switch (c) {            /* Command */
  1183.       case WILL:            /* Host says it will echo. */
  1184.         if (echo)            /* Only reply if change required. */
  1185.           return((tn_sopt(DO,x) < 0) ? -1 : 2); /* Please do. */
  1186.         else return(0);        /* Otherwise no change. */
  1187.       case WONT:            /* Host says it won't echo. */
  1188.         if (!echo)            /* If I'm full duplex */
  1189.           return ((tn_sopt(DONT,x) < 0) ? -1 : 1); /* Switch to half */
  1190.         else return(0);        /* Otherwise, no change.  */
  1191.       case DO:            /* Host wants me to echo */
  1192.         if (tn_sopt(WONT,x) < 0)    /* but the client never echoes */
  1193.           return(-1);        /* back to the server. */
  1194.       default:            /* Don't reply to anything else */
  1195.         return(0);
  1196.     }
  1197.  
  1198.       case TELOPT_SGA:            /* Suppress Go-Ahead */
  1199.     switch (c) {            /* Command... */
  1200.       case WONT:            /* Host says it won't. */
  1201.         if (!sgaflg) {
  1202.         sgaflg = 1;        /* Remember. */
  1203.         if (tn_sopt(DONT,x) < 0) /* acknowledge, */
  1204.           return(-1);
  1205.         }
  1206.         return(echo ? 0 : 1);    /* Switch to half duplex */
  1207.       case WILL:            /* Server says it will SGA */
  1208.         if (sgaflg || !dosga) {    /* ACK only if necessary */
  1209.         if (tn_sopt(DO,x) < 0)
  1210.           return(-1);
  1211.         sgaflg = 0;        /* Remember new SGA state. */
  1212.         }
  1213.         return(0);            /* But don't change echo state. */
  1214.     }
  1215.  
  1216. #ifdef TELOPT_TTYPE
  1217.       case TELOPT_TTYPE:        /* Terminal Type */
  1218.     switch (c) {
  1219.       case DO:            /* DO terminal type. */
  1220.         if (wttflg == 0) {        /* If I haven't said so before, */
  1221.         if (tn_sopt((CHAR)WILL,x) < 0) /* say I'll send it if asked. */
  1222.           return(-1);
  1223.         wttflg++;
  1224.         }
  1225.         return(0);
  1226.       case SB:
  1227.         debug(F100,"TELNET subnegotiation:","",0);
  1228.         n = flag = 0;        /* Flag for when done reading SB */
  1229.         while (n < TSBUFSIZ) {    /* Loop looking for IAC SE */
  1230.         if ((y = (*fn)(0)) < 0)    /* Read a byte */
  1231.           return(-1);
  1232.         y &= 0xff;        /* Make sure it's just 8 bits. */
  1233.         sb[n++] = y;        /* Deposit in buffer. */
  1234.         if (seslog)        /* Take care of session log */
  1235.           if (zchout(ZSFILE, (char) y) < 0)
  1236.             seslog = 0;
  1237.         if (y == IAC) {        /* If this is an IAC */
  1238.             if (flag) {        /* If previous char was IAC */
  1239.             n--;        /* it's quoted, keep one IAC */
  1240.             flag = 0;    /* and turn off the flag. */
  1241.             } else flag = 1;    /* Otherwise set the flag. */
  1242.         } else if (flag) {     /* Something else following IAC */
  1243.             if (y != SE)    /* If not SE, it's a protocol error */
  1244.               flag = 0;
  1245.             break;
  1246.         }
  1247.         }
  1248.         if (!flag) {        /* Make sure we got a valid SB */
  1249.         debug(F100, "TELNET Subnegotian prematurely broken", "",0);
  1250.         return(-1);
  1251.         }
  1252.         if (debses) {        /* Debug to screen. */
  1253.         int i;
  1254.         printf("<SB %s ",telopts[TELOPT_TTYPE]);
  1255.         for (i = 0; i < n-2; i++) printf("%02x",(unsigned int) sb[i]);
  1256.         printf(" IAC SE>");
  1257.         }
  1258.         debug(F101,"TELNET suboption<","",sb[0]);
  1259.         if (sb[0] == 1) {        /* SEND terminal type? */
  1260.         if (tn_sttyp() < 0)    /* Yes, so send it. */
  1261.           return(-1);
  1262.         }
  1263.       default:            /* Others, ignore */
  1264.         return(0);
  1265.     }
  1266. #endif /* TELOPT_TTYPE */
  1267.  
  1268.       default:                /* All others: refuse */
  1269.     switch(c) {
  1270.       case WILL:            /* You will? */
  1271.         if (tn_sopt(DONT,x) < 0)    /* Please don't. */
  1272.           return(-1);        /* (Could this cause a loop?) */
  1273.         break;
  1274.       case DO:            /* You want me to? */
  1275.         if (tn_sopt(WONT,x) < 0)    /* I won't. */
  1276.           return(-1);
  1277.         break;
  1278.       case DONT:            /* You don't want me to? */
  1279.         if (tn_sopt(WONT,x) < 0)    /* I won't. */
  1280.           return(-1);        /* (Could this cause a loop?) */
  1281.       case WONT:            /* You won't? */
  1282.         break;            /* I didn't want you to. */
  1283.     }                /* Anything else, treat as user data */
  1284.     return(0);
  1285.     }
  1286. #endif /* TNCODE */
  1287. }
  1288.  
  1289. /* Telnet send terminal type */
  1290. /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
  1291.  
  1292. int
  1293. tn_sttyp() {                /* Send telnet terminal type. */
  1294. #ifndef TNCODE
  1295.     debug(F100,"tn_sttyp no TNCODE","",0);
  1296.     return(0);
  1297. #else
  1298.     char *ttn; int ttl, i;        /* Name & length of terminal type. */
  1299.  
  1300.     if (ttnet != NET_TCPB) return(0);
  1301.     if (ttnproto != NP_TELNET) return(0);
  1302.  
  1303.     ttn = NULL;
  1304.  
  1305.     if (tn_term) {            /* Terminal type override? */
  1306.     debug(F110,"tn_sttyp",tn_term,0);
  1307.     if (*tn_term) ttn = tn_term;
  1308.     } else debug(F100,"tn_sttyp no term override","",0);
  1309. #ifndef datageneral
  1310.     if (!ttn)                /* If no override, */
  1311.       ttn = getenv("TERM");        /* get it from the environment. */
  1312. #endif /* datageneral */
  1313.     if ((ttn == ((char *)0)) || ((ttl = (int)strlen(ttn)) >= TSBUFSIZ)) {
  1314.     ttn = "UNKNOWN";
  1315.     ttl = 7;
  1316.     }
  1317.     sb[0] = (CHAR) IAC;            /* I Am a Command */
  1318.     sb[1] = (CHAR) SB;            /* Subnegotiation */
  1319.     sb[2] = TELOPT_TTYPE;        /* Terminal Type */
  1320.     sb[3] = (CHAR) 0;            /* Is... */
  1321.     for (i = 4; *ttn; ttn++,i++)    /* Copy and uppercase it */
  1322.       sb[i] = (islower(*ttn)) ? toupper(*ttn) : *ttn;
  1323.     ttn = sb;                /* Point back to beginning */
  1324.     sb[i++] = (CHAR) IAC;        /* End of Subnegotiation */
  1325.     sb[i++] = (CHAR) SE;        /* marked by IAC SE */
  1326.     if (ttol((CHAR *)sb,i) < 0)        /* Send it. */
  1327.       return(-1);
  1328. #ifdef DEBUG
  1329.     sb[i-2] = '\0';            /* For debugging */
  1330.     debug(F111,"telnet SB sent ttype",sb+4,ttl);
  1331. #endif /* DEBUG */
  1332.     if (debses)                /* Debug to screen. */
  1333.       printf("[SB TERMINAL TYPE 00 %s IAC SE]",sb+4);
  1334.     return(1);
  1335. #endif /* TNCODE */
  1336. }
  1337.  
  1338. #ifdef SUNX25
  1339. /*
  1340.   SunLink X.25 support by Marcello Frutig, Catholic University,
  1341.   Rio de Janeiro, Brazil, 1990.
  1342. */
  1343.  
  1344. /* PAD X.3, X.28 and X.29 support */
  1345.  
  1346. static CHAR x29err [MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
  1347.  
  1348.  
  1349. /* Initialize PAD */
  1350.  
  1351. extern CHAR padparms[MAXPADPARMS+1];
  1352.  
  1353. VOID
  1354. initpad() {
  1355.   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
  1356.   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
  1357.   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
  1358.   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
  1359.   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
  1360.   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
  1361.   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
  1362.   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
  1363.   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
  1364.   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
  1365.   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
  1366.   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
  1367.   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
  1368.   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
  1369.   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
  1370.   padparms[PAD_EDITING]                = 1;  /* can edit */
  1371.   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
  1372.   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
  1373.   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
  1374. }
  1375.  
  1376.  
  1377. /* Set PAD parameters */
  1378.  
  1379. VOID
  1380. setpad(s,n) CHAR *s; int n; {
  1381.     int i;
  1382.     CHAR *ps = s;
  1383.  
  1384.     for (i = 0; i < n; i++) {
  1385.         if (*ps > MAXPADPARMS)
  1386.       x29err[i+2] = *ps;
  1387.         else
  1388.       padparms[*ps] = *(ps+1);
  1389.         ps += 2;
  1390.     }
  1391. }
  1392.  
  1393. /* Read PAD parameters */
  1394.  
  1395. VOID
  1396. readpad(s,n,r) CHAR *s; int n; CHAR *r; {
  1397.     int i;
  1398.     CHAR *ps = s;
  1399.     CHAR *pr = r;
  1400.  
  1401.     *pr++ = X29_PARAMETER_INDICATION;
  1402.     for (i = 0; i < n; i++, ps++) {
  1403.          if (*ps > MAXPADPARMS) {
  1404.              x29err[i+2] = *ps++;
  1405.          } else {
  1406.              *pr++ = *ps;
  1407.              *pr++ = padparms[*ps++];
  1408.          }
  1409.     }
  1410. }
  1411.  
  1412. int
  1413. qbitpkt(s,n) CHAR *s; int n; {
  1414.     CHAR *ps = s;
  1415.     int x29cmd = *ps;
  1416.     CHAR *psa = s+1;
  1417.     CHAR x29resp[(MAXPADPARMS*2)+1];
  1418.  
  1419.     switch (x29cmd) {
  1420.  
  1421.         case X29_SET_PARMS:
  1422.             setpad (ps+1,n/2);
  1423.             if ((int)strlen(x29err) > 2) {
  1424.                 ttol (x29err,(int)strlen(x29err));
  1425.                 x29err[2] = '\0';
  1426.             }
  1427.             return (-2);
  1428.         case X29_READ_PARMS:
  1429.             readpad (ps+1,n/2,x29resp);
  1430.             setqbit ();
  1431.             ttol (x29resp,n+1);
  1432.             if ((int)strlen(x29err) > 2) {
  1433.                 ttol (x29err,(int)strlen(x29err));
  1434.                 x29err[2] = '\0';
  1435.             }
  1436.             resetqbit();
  1437.             break;
  1438.         case X29_SET_AND_READ_PARMS:
  1439.             setpad (ps+1,n/2);
  1440.             readpad (ps+1,n/2,x29resp);
  1441.             setqbit();
  1442.             ttol (x29resp,n+1);
  1443.             if ((int)strlen(x29err) > 2) {
  1444.                 ttol (x29err,(int)strlen(x29err));
  1445.                 x29err [2] = '\0';
  1446.             }
  1447.             resetqbit();
  1448.             return (-2);
  1449.         case X29_INVITATION_TO_CLEAR:
  1450.             (VOID) x25clear();
  1451.             return (-1) ;
  1452.         case X29_INDICATION_OF_BREAK:
  1453.         break;
  1454.     }
  1455.     return (0);
  1456. }
  1457.  
  1458. /* PAD break action processor */
  1459.  
  1460. VOID
  1461. breakact() {
  1462.     extern char x25obuf[MAXOX25];
  1463.     extern int obufl;
  1464.     extern int active;
  1465.     extern unsigned char tosend;
  1466.     static CHAR indbrk[3] = {
  1467.     X29_INDICATION_OF_BREAK,
  1468.     PAD_SUPPRESSION_OF_DATA,
  1469.     1
  1470.     };
  1471.     CHAR intudat, cause, diag;
  1472.  
  1473.     if (x25stat() < 0) return(0);   /* Ignore if no virtual call established */
  1474.  
  1475.     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
  1476.         if (ttol(x25obuf,obufl) < 0) {
  1477.             perror ("\r\nCan't send characters");
  1478.             active = 0;
  1479.         } else {
  1480.             bzero (x25obuf,sizeof(x25obuf));
  1481.             obufl = 0;
  1482.             tosend = 0;
  1483.         };
  1484.  
  1485.     switch (padparms[PAD_BREAK_ACTION]) {
  1486.  
  1487.        case 0 : break;            /* do nothing */
  1488.        case 1 : /* send interrupt packet with interrupt user data field = 1 */
  1489.             intudat = 1;
  1490.                 x25intr (intudat);
  1491.                 break;
  1492.        case 2 : /* send reset packet with cause and diag = 0 */
  1493.         cause = diag = 0;
  1494.                 x25reset (cause,diag);
  1495.                 break;
  1496.        case 5 : /* send interrupt packet with interrupt user data field = 0 */
  1497.         intudat = 0;
  1498.                 x25intr (intudat) ;
  1499.                 setqbit ();
  1500.             /* send indication of break without a parameter field */
  1501.                 ttoc(X29_INDICATION_OF_BREAK);
  1502.                 resetqbit ();
  1503.                 break;
  1504.        case 8 : active = 0;        /* leave data transfer */
  1505.                 conol ("\r\n");
  1506.                 break;
  1507.        case 21: /* send interrupt packet with interrupt user data field = 0 */
  1508.         intudat = 0;
  1509.                 x25intr (intudat);
  1510.                 setpad (indbrk+1,2);    /* set pad to discard input */
  1511.                 setqbit ();
  1512.         /* send indication of break with parameter field */
  1513.                 ttol (indbrk,sizeof(indbrk));
  1514.                 resetqbit ();
  1515.                 break;
  1516.      }
  1517. }
  1518.  
  1519. /* X.25 support functions */
  1520.  
  1521. X25_CAUSE_DIAG diag;
  1522.  
  1523. /*
  1524.   Convert a null-terminated string representing an X.121 address
  1525.   to a packed BCD form.
  1526. */
  1527.  
  1528. int
  1529. pkx121(str,bcd) char *str; CHAR *bcd; {
  1530.     int i, j;
  1531.     u_char c;
  1532.  
  1533.     i = j = 0;
  1534.     while (str[i]) {
  1535.         if ( i >= 15 || str [i] < '0' || str [i] > '9' )
  1536.       return (-1);
  1537.         c = str [i] - '0';
  1538.         if ( i & 1 )
  1539.       bcd [j++] |= c;
  1540.         else
  1541.       bcd [j] = c << 4;
  1542.         i++;
  1543.     }
  1544.     return (i);
  1545. }
  1546.  
  1547. /* Reads and prints X.25 diagnostic */
  1548.  
  1549. int
  1550. x25diag () {
  1551.     int i;
  1552.  
  1553.     bzero ((char *)&diag,sizeof(diag));
  1554.     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
  1555.         perror ("Reading X.25 diagnostic");
  1556.         return(-1);
  1557.     }
  1558.     if (diag.datalen > 0) {
  1559.         printf ("X.25 Diagnostic :");
  1560.         for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]);
  1561.         printf ("\r\n");
  1562.     }
  1563.     return(0);
  1564. }
  1565.  
  1566. /* X.25 Out-of-Band Signal Handler */
  1567.  
  1568. VOID
  1569. x25oobh() {
  1570.     int oobtype;
  1571.     u_char oobdata;
  1572.  
  1573.     (VOID) signal(SIGURG,x25oobh);
  1574.     do {
  1575.         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
  1576.             perror ("Getting signal type");
  1577.             return;
  1578.         }
  1579.         switch (oobtype) {
  1580.       case INT_DATA:
  1581.         if (recv(ttyfd,oobdata,1,MSG_OOB) < 0) {
  1582.         perror ("Receiving X.25 interrupt data");
  1583.         return;
  1584.         }
  1585.         printf ("\r\nInterrupt received, data = %d\r\n", oobdata);
  1586.         break;
  1587.       case VC_RESET:
  1588.         printf ("\r\nVirtual circuit reset\r\n");
  1589.         x25diag ();
  1590.         break;
  1591.       case N_RESETS:
  1592.         printf ("\r\nReset timeout\r\n");
  1593.         break;
  1594.       case N_CLEARS:
  1595.         printf ("\r\nClear timeout\r\n");
  1596.         break;
  1597.       case MSG_TOO_LONG:
  1598.         printf ("\r\nMessage discarded, too long\r\n");
  1599.         break;
  1600.       default:
  1601.         if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
  1602.         break;
  1603.     }
  1604.     } while (oobtype);
  1605. }
  1606.  
  1607. /* Send a X.25 interrupt packet */
  1608.  
  1609. int
  1610. #ifdef CK_ANSIC
  1611. x25intr(char intr)
  1612. #else
  1613. x25intr(intr) char intr;
  1614. #endif /* CK_ANSIC */
  1615. /* x25intr */ {
  1616.     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
  1617.     debug(F100,"X.25 intr","",0);
  1618.     return(0);
  1619. }
  1620.  
  1621. /* Reset X.25 virtual circuit */
  1622. int
  1623. #ifdef CK_ANSIC
  1624. x25reset(char cause, char diagn)
  1625. #else
  1626. x25reset(cause, diagn) char cause; char diagn;
  1627. #endif /* CK_ANSIC */
  1628. /* x25reset */ {
  1629.     bzero ((char *)&diag,sizeof(diag));
  1630.     diag.flags   = 0;
  1631.     diag.datalen = 2;
  1632.     diag.data[0] = cause;
  1633.     diag.data[1] = diagn;
  1634.     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
  1635.       return(-1);
  1636.     debug(F100,"X.25 reset","",0);
  1637.     return(0);
  1638. }
  1639.  
  1640. /* Clear X.25 virtual circuit */
  1641. int
  1642. x25clear() {
  1643.     int i;
  1644.     debug(F100,"X.25 clear","",0);
  1645.     bzero ((char *)&diag,sizeof(diag));
  1646.     diag.flags = (1 << DIAG_TYPE);
  1647.     diag.datalen = 2;
  1648.     diag.data[0] = 0;
  1649.     diag.data[1] = 0;
  1650.     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
  1651.     return(ttclos(0));            /* Close socket */
  1652. }
  1653.  
  1654. /* X.25 status */
  1655. int
  1656. x25stat() {
  1657.     if (ttyfd < 0) return (-1);
  1658.     return(0);
  1659. }
  1660.  
  1661. /* Set Q_BIT on */
  1662. VOID
  1663. setqbit() {
  1664.     static int qbiton = 1 << Q_BIT;
  1665.     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
  1666. }
  1667.  
  1668. /* Set Q_BIT off */
  1669. VOID
  1670. resetqbit() {
  1671.     static int qbitoff = 0;
  1672.     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
  1673. }
  1674.  
  1675. /* Read n characters from X.25 circuit into buf */
  1676.  
  1677. int
  1678. x25xin(n,buf) int n; CHAR *buf; {
  1679.     register int x, c;
  1680.     int qpkt;
  1681.  
  1682.     do {
  1683.     x = read(ttyfd,buf,n);
  1684.     if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
  1685.         /* If return -1 : invitation to clear; -2 : PAD changes */
  1686.         if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
  1687.         qpkt = 1;
  1688.     } else qpkt = 0;
  1689.     } while (qpkt);
  1690.     if (x > 0) buf[x] = '\0';
  1691.     if (x < 1) x = -1;
  1692.     debug(F101,"x25xin x","",x);
  1693.  
  1694.     return(x);
  1695. }
  1696.  
  1697. #ifdef COMMENT /* NO LONGER NEEDED! */
  1698. /* X.25 read a line */
  1699.  
  1700. int
  1701. #ifdef PARSENSE
  1702. #ifdef CK_ANSIC
  1703. x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
  1704. #else
  1705. x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
  1706. #endif /* CK_ANSIC */
  1707. #else /* not PARSENSE */
  1708. #ifdef CK_ANSIC
  1709. x25inl(CHAR *dest, int max,int timo, CHAR eol)
  1710. #else
  1711. x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
  1712. #endif /* __SDTC__ */
  1713. #endif /* PARSENSE */
  1714. /* x25inl */ {
  1715.     CHAR *pdest;
  1716.     int pktype, goteol, rest, n;
  1717.     int i, flag = 0;
  1718.     extern int ttprty, ttpflg;
  1719.     int ttpmsk;
  1720.  
  1721.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
  1722.  
  1723.     debug(F101,"x25inl max","",max);
  1724.     debug(F101,"x25inl eol","",eol);
  1725.     pdest  = dest;
  1726.     rest   = max;
  1727.     goteol = 0;
  1728.     do {
  1729.     n = read(ttyfd,pdest,rest);
  1730.     n--;
  1731.     pktype = *pdest & 0x7f;
  1732.     switch (pktype) {
  1733.       case 1 << Q_BIT:
  1734.         if (qbitpkt(pdest+1,--n) < 0) return(-2);
  1735.         break;
  1736.       default:
  1737.         if (flag == 0) { /* if not in packet, search start */
  1738.         for (i = 1; (i < n) &&
  1739.              !(flag = ((dest[i] & 0x7f) == start));
  1740.              i++);
  1741.         if (flag == 0) { /* not found, discard junk */
  1742.             debug(F101,"x25inl skipping","",n);
  1743.             continue;
  1744.         } else {        /* found, discard junk before start */
  1745.             int k;
  1746.             n = n - i + 1;
  1747.             for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
  1748.         }
  1749.         }
  1750.         for (i = 0; (i < n) && /* search for eol */
  1751.          !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
  1752.          i++,pdest++);
  1753.         *pdest = '\0';
  1754.         rest -= n;
  1755.     }
  1756.     } while ( (rest > 0) && (!goteol) );
  1757.  
  1758.     if (goteol) {
  1759.     n = max - rest;
  1760.     debug (F111,"x25inl X.25 got",(char *) dest,n);
  1761.     if (timo) ttimoff();
  1762.     if (ttpflg++ == 0 && ttprty == 0) {
  1763.         if ((ttprty = parchk(dest,start,n)) > 0) {
  1764.         int j;
  1765.         debug(F101,"x25inl senses parity","",ttprty);
  1766.         debug(F110,"x25inl packet before",(char *)dest,0);
  1767.         ttpmsk = 0x7f;
  1768.         for (j = 0; j < n; j++)
  1769.           dest[j] &= 0x7f; /* Strip parity from packet */
  1770.         debug(F110,"x25inl packet after ",dest,0);
  1771.         } else {
  1772.         debug(F101,"parchk","",ttprty);
  1773.         if (ttprty < 0) { ttprty = 0; n = -1; }
  1774.         }
  1775.     }
  1776.     ttimoff();
  1777.     return(n);
  1778.     }
  1779.     ttimoff();
  1780.     return(-1);
  1781. }
  1782. #endif /* COMMENT */
  1783. #endif /* SUNX25 */
  1784.  
  1785. #endif /* NETCONN */
  1786.